using System;
using System.Collections.Generic;

namespace DA.AnimGraph {

    public enum AGRuntimeType : ushort {
        slot_node_start = 1000,
        SlotNode,
        slot_node_end,

        // 采样节点
        sample_node_start = 2000,
        ClipNode,
        SequenceNode,
        BlendSpace2DNode,
        BlendSpace1DNode,
        sample_node_end,

        // 混合节点
        blend_node_start = 3000,
        SimpleBlendNode,
        LayerBlendNode,
        SelectNode,
        StateMachineNode,
        AxisBlend1DNode,
        RevolveNode,
        blend_node_end,

        // 装饰节点
        decorate_node_start = 4000,
        decorate_node_end,

        // perk
        perk_start = 5000,
        TimelinePerk,
        SyncGroupPerk = 5100,
        CurveSamplerPerk = 5200,
        perk_end,

        // 过渡
        transition_condition_start = 9000,
        TransitionCondition_ExitTime,
        TransitionCondition_Blackboard,
        transition_condition_end,
    }

    public class AGRuntimeTypeRegister {
        private static AGRuntimeTypeRegister instance;

        public static AGRuntimeTypeRegister GetInstance() {
            if (instance == null) {
                instance = new AGRuntimeTypeRegister();
            }
            return instance;
        }

        private AGRuntimeTypeRegister() {
            Node();
            Perk();
            TransitionCondition();
        }

        private Dictionary<AGRuntimeType, NodeVirtualTable> nodeVirtualTables;
        private Dictionary<AGRuntimeType, PerkVirtualTable> perkVirtualTables;
        private Dictionary<AGRuntimeType, TransitionConditionVirtualTable> transitionConditionVirtualTables;

        private Dictionary<Type, AGRuntimeType> type2Enum = new() {
            { typeof(SlotNode), AGRuntimeType.SlotNode },
            { typeof(ClipNode), AGRuntimeType.ClipNode },
            { typeof(SequenceNode), AGRuntimeType.SequenceNode },
            { typeof(BlendSpace2DNode), AGRuntimeType.BlendSpace2DNode },
            { typeof(BlendSpace1DNode), AGRuntimeType.BlendSpace1DNode },
            { typeof(SimpleBlendNode), AGRuntimeType.SimpleBlendNode },
            { typeof(LayerBlendNode), AGRuntimeType.LayerBlendNode },
            { typeof(SelectNode), AGRuntimeType.SelectNode },
            { typeof(StateMachineNode), AGRuntimeType.StateMachineNode },
            { typeof(AxisBlend1DNode), AGRuntimeType.AxisBlend1DNode },
            { typeof(RevolveNode), AGRuntimeType.RevolveNode },

            { typeof(TimelinePerk), AGRuntimeType.TimelinePerk },
            { typeof(SyncGroupPerk), AGRuntimeType.SyncGroupPerk },
            { typeof(CurveSamplerPerk), AGRuntimeType.CurveSamplerPerk },

            { typeof(TransitionCondition_ExitTime), AGRuntimeType.TransitionCondition_ExitTime },
            { typeof(TransitionCondition_Blackboard), AGRuntimeType.TransitionCondition_Blackboard },
        };

        void Node() {
            nodeVirtualTables = new() {
                { AGRuntimeType.SlotNode, SlotNode.GetVirtualFunction() },
                { AGRuntimeType.ClipNode, ClipNode.GetVirtualFunction() },
                { AGRuntimeType.SequenceNode, SequenceNode.GetVirtualFunction() },
                { AGRuntimeType.BlendSpace2DNode, BlendSpace2DNode.GetVirtualFunction() },
                { AGRuntimeType.BlendSpace1DNode, BlendSpace1DNode.GetVirtualFunction() },
                { AGRuntimeType.SimpleBlendNode, SimpleBlendNode.GetVirtualFunction() },
                { AGRuntimeType.LayerBlendNode, LayerBlendNode.GetVirtualFunction() },
                { AGRuntimeType.SelectNode, SelectNode.GetVirtualFunction() },
                { AGRuntimeType.StateMachineNode, StateMachineNode.GetVirtualFunction() },
                { AGRuntimeType.AxisBlend1DNode, AxisBlend1DNode.GetVirtualFunction() },
                { AGRuntimeType.RevolveNode, RevolveNode.GetVirtualFunction() },
            };
        }
        void Perk() {
            perkVirtualTables = new() {
                { AGRuntimeType.TimelinePerk, TimelinePerk.GetVirtualFunction() },
                { AGRuntimeType.SyncGroupPerk, SyncGroupPerk.GetVirtualFunction() },
                { AGRuntimeType.CurveSamplerPerk, CurveSamplerPerk.GetVirtualFunction() },
            };
        }
        void TransitionCondition() {
            transitionConditionVirtualTables = new() {
                { AGRuntimeType.TransitionCondition_ExitTime, TransitionCondition_ExitTime.GetVirtualFunction() },
                { AGRuntimeType.TransitionCondition_Blackboard, TransitionCondition_Blackboard.GetVirtualFunction() },
            };
        }

        public AGRuntimeType GetEnumByType(Type type) {
            if (type2Enum.TryGetValue(type, out var result)) {
                return result;
            }
            throw new ArgumentNullException($"can't find {type} in type2Enum");
        }
        public NodeVirtualTable GetNodeVirtualTable(AGRuntimeType type) {
            if (nodeVirtualTables.TryGetValue(type, out var result)) {
                return result;
            }
            throw new ArgumentNullException($"can't find {type} in nodeVirtualTables");
        }
        public PerkVirtualTable GetPerkVirtualTable(AGRuntimeType type) {
            if (perkVirtualTables.TryGetValue(type, out var result)) {
                return result;
            }
            throw new ArgumentNullException($"can't find {type} in perkVirtualTables");
        }
        public TransitionConditionVirtualTable GetTransitionConditionVirtualTable(AGRuntimeType type) {
            if (transitionConditionVirtualTables.TryGetValue(type, out var result)) {
                return result;
            }
            throw new ArgumentNullException($"can't find {type} in transitionConditionVirtualTables");
        }

    }
}
